package jmind.core.redis;


/**
 * 简单redis分布式锁的实现
 * Redlock 算法着眼于满足分布式锁的三个要素：

 安全性：保证互斥，任何时间至多只有一个客户端可以持有锁
 免死锁：即使当前持有锁的客户端崩溃或者从集群中被分开了，其它客户端最终总是能够获得锁。
 容错性：只要大部分的 Redis 节点在线，那么客户端就能够获取和释放锁。
 * 如果想要强大的分布式锁请使用 RedissonLock
 * @see http://blog.csdn.net/csujiangyu/article/details/51005342 RedissonManager
 */
public class RedisDistributedLock  {



    private  final int EXPIRE_TIME ;
    private  final int WAIT_TIME;
    private  final Redis jedis;

    /**
     * @see http://blog.csdn.net/java2000_wl
     * @param redis
     * @param expireTime  缓存过期时间
     * @param waitTime 每次轮询等待时间
     */
    public RedisDistributedLock(Redis redis,int expireTime,int waitTime) {
        this.EXPIRE_TIME=expireTime;
        this.WAIT_TIME=waitTime;
        this.jedis = redis;
    }

    /**
     * 获取锁  如果锁可用   立即返回true，  否则返回false
     * @author http://blog.csdn.net/java2000_wl

     * @return
     */
    public boolean tryLock(String key) {
        return tryLock(key, 0L);
    }

    /**
     * 锁在给定的等待时间内空闲，则获取锁成功 返回true， 否则返回false
     * @author http://blog.csdn.net/java2000_wl

     *      long, java.util.concurrent.TimeUnit)
     * @param timeout 超时时间，毫秒
     * @return
     */
    public boolean tryLock(String key, long timeout) {
            long nano = System.currentTimeMillis();
            do {

                Long i = jedis.setnx(key, key);
                if (i == 1) {
                    jedis.expire(key, EXPIRE_TIME);
                    return Boolean.TRUE;
                }
                if (timeout == 0) {
                    break;
                }
                try {
                    Thread.sleep(WAIT_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } while ((System.currentTimeMillis() - nano) <= timeout);


        return Boolean.FALSE;
    }

    /**
     * 如果锁空闲立即返回   获取失败 一直等待
     */
    public void lock(String key) {
       try {
           do {
               Long i = jedis.setnx(key, key);
               if (i == 1) {
                   jedis.expire(key, EXPIRE_TIME);
                   return;
               }
               Thread.sleep(WAIT_TIME);
           } while (true);
       }catch (Exception e){

       }
    }

    /**
     * 释放锁
     * @author http://blog.csdn.net/java2000_wl


     */
    public void unLock(String key) {
        jedis.del(key);
    }

//    /**
//     * 批量获取锁  如果全部获取   立即返回true, 部分获取失败 返回false
//     * @author http://blog.csdn.net/java2000_wl
//     * @date 2013-7-22 下午10:27:44
//     * @see com.fx.platform.components.lock.IBatchBillLockHandler#tryLock(java.util.List)
//     * @param billIdentifyList
//     * @return
//     */
//    public boolean tryLock(List<IBillIdentify> billIdentifyList) {
//        return tryLock(billIdentifyList, 0L, null);
//    }
//
//    /**
//     * 锁在给定的等待时间内空闲，则获取锁成功 返回true， 否则返回false
//     * @author http://blog.csdn.net/java2000_wl
//     * @param billIdentifyList
//     * @param timeout
//     * @param unit
//     * @return
//     */
//    public boolean tryLock(List<IBillIdentify> billIdentifyList, long timeout, TimeUnit unit) {
//        Jedis jedis = null;
//        try {
//            List<String> needLocking = new CopyOnWriteArrayList<String>();
//            List<String> locked = new CopyOnWriteArrayList<String>();
//            jedis = getResource();
//            long nano = System.nanoTime();
//            do {
//                // 构建pipeline，批量提交
//                Pipeline pipeline = jedis.pipelined();
//                for (IBillIdentify identify : billIdentifyList) {
//                    String key = (String) identify.uniqueIdentify();
//                    needLocking.add(key);
//                    pipeline.setnx(key, key);
//                }
//                LOGGER.debug("try lock keys: " + needLocking);
//                // 提交redis执行计数
//                List<Object> results = pipeline.syncAndReturnAll();
//                for (int i = 0; i < results.size(); ++i) {
//                    Long result = (Long) results.get(i);
//                    String key = needLocking.get(i);
//                    if (result == 1) {    // setnx成功，获得锁
//                        jedis.expire(key, DEFAULT_BATCH_EXPIRE_TIME);
//                        locked.add(key);
//                    }
//                }
//                needLocking.removeAll(locked);    // 已锁定资源去除
//
//                if (CollectionUtils.isEmpty(needLocking)) {
//                    return true;
//                } else {
//                    // 部分资源未能锁住
//                    LOGGER.debug("keys: " + needLocking + " locked by another business：");
//                }
//
//                if (timeout == 0) {
//                    break;
//                }
//                Thread.sleep(500);
//            } while ((System.nanoTime() - nano) < unit.toNanos(timeout));
//
//            // 得不到锁，释放锁定的部分对象，并返回失败
//            if (!CollectionUtils.isEmpty(locked)) {
//                jedis.del(locked.toArray(new String[0]));
//            }
//            return false;
//        } catch (JedisConnectionException je) {
//            LOGGER.error(je.getMessage(), je);
//            returnBrokenResource(jedis);
//        } catch (Exception e) {
//            LOGGER.error(e.getMessage(), e);
//        } finally {
//            returnResource(jedis);
//        }
//        return true;
//    }
//
//    /**
//     * 批量释放锁
//     * @author http://blog.csdn.net/java2000_wl
//     * @see com.fx.platform.components.lock.IBatchBillLockHandler#unLock(java.util.List)
//     * @param billIdentifyList
//     */
//    public void unLock(List<IBillIdentify> billIdentifyList) {
//        List<String> keys = new CopyOnWriteArrayList<String>();
//        for (IBillIdentify identify : billIdentifyList) {
//            String key = (String) identify.uniqueIdentify();
//            keys.add(key);
//        }
//        Jedis jedis = null;
//        try {
//            jedis = getResource();
//            jedis.del(keys.toArray(new String[0]));
//            LOGGER.debug("release lock, keys :" + keys);
//        } catch (JedisConnectionException je) {
//            LOGGER.error(je.getMessage(), je);
//            returnBrokenResource(jedis);
//        } catch (Exception e) {
//            LOGGER.error(e.getMessage(), e);
//        } finally {
//            returnResource(jedis);
//        }
//    }


    }